/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"mozilla/dom/ScriptSettings.h"#include"mozilla/ThreadLocal.h"#include"mozilla/Assertions.h"#include"mozilla/CycleCollectedJSContext.h"#include"jsapi.h"#include"xpcpublic.h"#include"nsIGlobalObject.h"#include"nsIDocShell.h"#include"nsIScriptGlobalObject.h"#include"nsIScriptContext.h"#include"nsContentUtils.h"#include"nsGlobalWindow.h"#include"nsPIDOMWindow.h"#include"nsTArray.h"#include"nsJSUtils.h"#include"nsDOMJSUtils.h"#include"WorkerPrivate.h"namespacemozilla{namespacedom{staticMOZ_THREAD_LOCAL(ScriptSettingsStackEntry*)sScriptSettingsTLS;staticboolsScriptSettingsTLSInitialized;classScriptSettingsStack{public:staticScriptSettingsStackEntry*Top(){returnsScriptSettingsTLS.get();}staticvoidPush(ScriptSettingsStackEntry*aEntry){MOZ_ASSERT(!aEntry->mOlder);// Whenever JSAPI use is disabled, the next stack entry pushed must// not be an AutoIncumbentScript.MOZ_ASSERT_IF(!Top()||Top()->NoJSAPI(),!aEntry->IsIncumbentScript());// Whenever the top entry is not an incumbent canidate, the next stack entry// pushed must not be an AutoIncumbentScript.MOZ_ASSERT_IF(Top()&&!Top()->IsIncumbentCandidate(),!aEntry->IsIncumbentScript());aEntry->mOlder=Top();sScriptSettingsTLS.set(aEntry);}staticvoidPop(ScriptSettingsStackEntry*aEntry){MOZ_ASSERT(aEntry==Top());sScriptSettingsTLS.set(aEntry->mOlder);}staticnsIGlobalObject*IncumbentGlobal(){ScriptSettingsStackEntry*entry=Top();while(entry){if(entry->IsIncumbentCandidate()){returnentry->mGlobalObject;}entry=entry->mOlder;}returnnullptr;}staticScriptSettingsStackEntry*EntryPoint(){ScriptSettingsStackEntry*entry=Top();while(entry){if(entry->IsEntryCandidate()){returnentry;}entry=entry->mOlder;}returnnullptr;}staticnsIGlobalObject*EntryGlobal(){ScriptSettingsStackEntry*entry=EntryPoint();if(!entry){returnnullptr;}returnentry->mGlobalObject;}#ifdef DEBUGstaticScriptSettingsStackEntry*TopNonIncumbentScript(){ScriptSettingsStackEntry*entry=Top();while(entry){if(!entry->IsIncumbentScript()){returnentry;}entry=entry->mOlder;}returnnullptr;}#endif // DEBUG};staticunsignedlonggRunToCompletionListeners=0;voidUseEntryScriptProfiling(){MOZ_ASSERT(NS_IsMainThread());++gRunToCompletionListeners;}voidUnuseEntryScriptProfiling(){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(gRunToCompletionListeners>0);--gRunToCompletionListeners;}voidInitScriptSettings(){boolsuccess=sScriptSettingsTLS.init();if(!success){MOZ_CRASH();}sScriptSettingsTLS.set(nullptr);sScriptSettingsTLSInitialized=true;}voidDestroyScriptSettings(){MOZ_ASSERT(sScriptSettingsTLS.get()==nullptr);}boolScriptSettingsInitialized(){returnsScriptSettingsTLSInitialized;}ScriptSettingsStackEntry::ScriptSettingsStackEntry(nsIGlobalObject*aGlobal,TypeaType):mGlobalObject(aGlobal),mType(aType),mOlder(nullptr){MOZ_ASSERT_IF(IsIncumbentCandidate()&&!NoJSAPI(),mGlobalObject);MOZ_ASSERT(!mGlobalObject||mGlobalObject->GetGlobalJSObject(),"Must have an actual JS global for the duration on the stack");MOZ_ASSERT(!mGlobalObject||JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),"No outer windows allowed");}ScriptSettingsStackEntry::~ScriptSettingsStackEntry(){// We must have an actual JS global for the entire time this is on the stack.MOZ_ASSERT_IF(mGlobalObject,mGlobalObject->GetGlobalJSObject());}// If the entry or incumbent global ends up being something that the subject// principal doesn't subsume, we don't want to use it. This never happens on// the web, but can happen with asymmetric privilege relationships (i.e.// ExpandedPrincipal and System Principal).//// The most correct thing to use instead would be the topmost global on the// callstack whose principal is subsumed by the subject principal. But that's// hard to compute, so we just substitute the global of the current// compartment. In practice, this is fine.//// Note that in particular things like://// |SpecialPowers.wrap(crossOriginWindow).eval(open())|//// trigger this case. Although both the entry global and the current global// have normal principals, the use of Gecko-specific System-Principaled JS// puts the code from two different origins on the callstack at once, which// doesn't happen normally on the web.staticnsIGlobalObject*ClampToSubject(nsIGlobalObject*aGlobalOrNull){if(!aGlobalOrNull||!NS_IsMainThread()){returnaGlobalOrNull;}nsIPrincipal*globalPrin=aGlobalOrNull->PrincipalOrNull();NS_ENSURE_TRUE(globalPrin,GetCurrentGlobal());if(!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()->SubsumesConsideringDomain(globalPrin)){returnGetCurrentGlobal();}returnaGlobalOrNull;}nsIGlobalObject*GetEntryGlobal(){returnClampToSubject(ScriptSettingsStack::EntryGlobal());}nsIDocument*GetEntryDocument(){nsIGlobalObject*global=GetEntryGlobal();nsCOMPtr<nsPIDOMWindowInner>entryWin=do_QueryInterface(global);// If our entry global isn't a window, see if it's an addon scope associated// with a window. If it is, the caller almost certainly wants that rather// than null.if(!entryWin&&global){if(auto*win=xpc::AddonWindowOrNull(global->GetGlobalJSObject())){entryWin=win->AsInner();}}returnentryWin?entryWin->GetExtantDoc():nullptr;}nsIGlobalObject*GetIncumbentGlobal(){// We need the current JSContext in order to check the JS for// scripted frames that may have appeared since anyone last// manipulated the stack. If it's null, that means that there// must be no entry global on the stack, and therefore no incumbent// global either.JSContext*cx=nsContentUtils::GetCurrentJSContextForThread();if(!cx){MOZ_ASSERT(ScriptSettingsStack::EntryGlobal()==nullptr);returnnullptr;}// See what the JS engine has to say. If we've got a scripted caller// override in place, the JS engine will lie to us and pretend that// there's nothing on the JS stack, which will cause us to check the// incumbent script stack below.if(JSObject*global=JS::GetScriptedCallerGlobal(cx)){returnClampToSubject(xpc::NativeGlobal(global));}// Ok, nothing from the JS engine. Let's use whatever's on the// explicit stack.returnClampToSubject(ScriptSettingsStack::IncumbentGlobal());}nsIGlobalObject*GetCurrentGlobal(){JSContext*cx=nsContentUtils::GetCurrentJSContextForThread();if(!cx){returnnullptr;}JSObject*global=JS::CurrentGlobalOrNull(cx);if(!global){returnnullptr;}returnxpc::NativeGlobal(global);}nsIPrincipal*GetWebIDLCallerPrincipal(){MOZ_ASSERT(NS_IsMainThread());ScriptSettingsStackEntry*entry=ScriptSettingsStack::EntryPoint();// If we have an entry point that is not NoJSAPI, we know it must be an// AutoEntryScript.if(!entry||entry->NoJSAPI()){returnnullptr;}AutoEntryScript*aes=static_cast<AutoEntryScript*>(entry);returnaes->mWebIDLCallerPrincipal;}boolIsJSAPIActive(){ScriptSettingsStackEntry*topEntry=ScriptSettingsStack::Top();returntopEntry&&!topEntry->NoJSAPI();}namespacedanger{JSContext*GetJSContext(){returnCycleCollectedJSContext::Get()->Context();}}// namespace dangerJS::RootingContext*RootingCx(){returnCycleCollectedJSContext::Get()->RootingCx();}AutoJSAPI::AutoJSAPI():ScriptSettingsStackEntry(nullptr,eJSAPI),mCx(nullptr),mIsMainThread(false)// For lack of anything better{}AutoJSAPI::~AutoJSAPI(){if(!mCx){// No need to do anything here: we never managed to Init, so can't have an// exception on our (nonexistent) JSContext. We also don't need to restore// any state on it. Finally, we never made it to pushing outselves onto the// ScriptSettingsStack, so shouldn't pop.MOZ_ASSERT(ScriptSettingsStack::Top()!=this);return;}ReportException();if(mOldWarningReporter.isSome()){JS::SetWarningReporter(cx(),mOldWarningReporter.value());}// Leave the request before popping.if(mIsMainThread){mAutoRequest.reset();}ScriptSettingsStack::Pop(this);}voidWarningOnlyErrorReporter(JSContext*aCx,JSErrorReport*aRep);voidAutoJSAPI::InitInternal(nsIGlobalObject*aGlobalObject,JSObject*aGlobal,JSContext*aCx,boolaIsMainThread){MOZ_ASSERT(aCx);MOZ_ASSERT(aCx==danger::GetJSContext());MOZ_ASSERT(aIsMainThread==NS_IsMainThread());MOZ_ASSERT(bool(aGlobalObject)==bool(aGlobal));MOZ_ASSERT_IF(aGlobalObject,aGlobalObject->GetGlobalJSObject()==aGlobal);#ifdef DEBUGboolhaveException=JS_IsExceptionPending(aCx);#endif // DEBUGmCx=aCx;mIsMainThread=aIsMainThread;mGlobalObject=aGlobalObject;if(aIsMainThread){// We _could_ just unconditionally emplace mAutoRequest here. It's just not// needed on worker threads, and we're hoping to kill it on the main thread// too.mAutoRequest.emplace(mCx);}if(aGlobal){JS::ExposeObjectToActiveJS(aGlobal);}mAutoNullableCompartment.emplace(mCx,aGlobal);ScriptSettingsStack::Push(this);mOldWarningReporter.emplace(JS::GetWarningReporter(aCx));JS::SetWarningReporter(aCx,WarningOnlyErrorReporter);#ifdef DEBUGif(haveException){JS::Rooted<JS::Value>exn(aCx);JS_GetPendingException(aCx,&exn);JS_ClearPendingException(aCx);if(exn.isObject()){JS::Rooted<JSObject*>exnObj(aCx,&exn.toObject());// Make sure we can actually read things from it. This UncheckedUwrap is// safe because we're only getting data for a debug printf. In// particular, we do not expose this data to anyone, which is very// important; otherwise it could be a cross-origin information leak.exnObj=js::UncheckedUnwrap(exnObj);JSAutoCompartmentac(aCx,exnObj);nsAutoJSStringstack,filename,name,message;int32_tline;JS::Rooted<JS::Value>tmp(aCx);if(!JS_GetProperty(aCx,exnObj,"filename",&tmp)){JS_ClearPendingException(aCx);}if(tmp.isUndefined()){if(!JS_GetProperty(aCx,exnObj,"fileName",&tmp)){JS_ClearPendingException(aCx);}}if(!filename.init(aCx,tmp)){JS_ClearPendingException(aCx);}if(!JS_GetProperty(aCx,exnObj,"stack",&tmp)||!stack.init(aCx,tmp)){JS_ClearPendingException(aCx);}if(!JS_GetProperty(aCx,exnObj,"name",&tmp)||!name.init(aCx,tmp)){JS_ClearPendingException(aCx);}if(!JS_GetProperty(aCx,exnObj,"message",&tmp)||!message.init(aCx,tmp)){JS_ClearPendingException(aCx);}if(!JS_GetProperty(aCx,exnObj,"lineNumber",&tmp)||!JS::ToInt32(aCx,tmp,&line)){JS_ClearPendingException(aCx);line=0;}printf_stderr("PREEXISTING EXCEPTION OBJECT: '%s: %s'\n%s:%d\n%s\n",NS_ConvertUTF16toUTF8(name).get(),NS_ConvertUTF16toUTF8(message).get(),NS_ConvertUTF16toUTF8(filename).get(),line,NS_ConvertUTF16toUTF8(stack).get());}else{// It's a primitive... not much we can do other than stringify it.nsAutoJSStringexnStr;if(!exnStr.init(aCx,exn)){JS_ClearPendingException(aCx);}printf_stderr("PREEXISTING EXCEPTION PRIMITIVE: %s\n",NS_ConvertUTF16toUTF8(exnStr).get());}MOZ_ASSERT(false,"We had an exception; we should not have");}#endif // DEBUG}AutoJSAPI::AutoJSAPI(nsIGlobalObject*aGlobalObject,boolaIsMainThread,TypeaType):ScriptSettingsStackEntry(aGlobalObject,aType),mIsMainThread(aIsMainThread){MOZ_ASSERT(aGlobalObject);MOZ_ASSERT(aGlobalObject->GetGlobalJSObject(),"Must have a JS global");MOZ_ASSERT(aIsMainThread==NS_IsMainThread());InitInternal(aGlobalObject,aGlobalObject->GetGlobalJSObject(),danger::GetJSContext(),aIsMainThread);}voidAutoJSAPI::Init(){MOZ_ASSERT(!mCx,"An AutoJSAPI should only be initialised once");InitInternal(/* aGlobalObject */nullptr,/* aGlobal */nullptr,danger::GetJSContext(),NS_IsMainThread());}boolAutoJSAPI::Init(nsIGlobalObject*aGlobalObject,JSContext*aCx){MOZ_ASSERT(!mCx,"An AutoJSAPI should only be initialised once");MOZ_ASSERT(aCx);if(NS_WARN_IF(!aGlobalObject)){returnfalse;}JSObject*global=aGlobalObject->GetGlobalJSObject();if(NS_WARN_IF(!global)){returnfalse;}InitInternal(aGlobalObject,global,aCx,NS_IsMainThread());returntrue;}boolAutoJSAPI::Init(nsIGlobalObject*aGlobalObject){returnInit(aGlobalObject,danger::GetJSContext());}boolAutoJSAPI::Init(JSObject*aObject){returnInit(xpc::NativeGlobal(aObject));}boolAutoJSAPI::Init(nsPIDOMWindowInner*aWindow,JSContext*aCx){returnInit(nsGlobalWindow::Cast(aWindow),aCx);}boolAutoJSAPI::Init(nsPIDOMWindowInner*aWindow){returnInit(nsGlobalWindow::Cast(aWindow));}boolAutoJSAPI::Init(nsGlobalWindow*aWindow,JSContext*aCx){returnInit(static_cast<nsIGlobalObject*>(aWindow),aCx);}boolAutoJSAPI::Init(nsGlobalWindow*aWindow){returnInit(static_cast<nsIGlobalObject*>(aWindow));}// Even with autoJSAPIOwnsErrorReporting, the JS engine still sends warning// reports to the JSErrorReporter as soon as they are generated. These go// directly to the console, so we can handle them easily here.//// Eventually, SpiderMonkey will have a special-purpose callback for warnings// only.voidWarningOnlyErrorReporter(JSContext*aCx,JSErrorReport*aRep){MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));if(!NS_IsMainThread()){// Reporting a warning on workers is a bit complicated because we have to// climb our parent chain until we get to the main thread. So go ahead and// just go through the worker ReportError codepath here.//// That said, it feels like we should be able to short-circuit things a bit// here by posting an appropriate runnable to the main thread directly...// Worth looking into sometime.workers::WorkerPrivate*worker=workers::GetWorkerPrivateFromContext(aCx);MOZ_ASSERT(worker);worker->ReportError(aCx,JS::ConstUTF8CharsZ(),aRep);return;}RefPtr<xpc::ErrorReport>xpcReport=newxpc::ErrorReport();nsGlobalWindow*win=xpc::CurrentWindowOrNull(aCx);if(!win){// We run addons in a separate privileged compartment, but if we're in an// addon compartment we should log warnings to the console of the associated// DOM Window.win=xpc::AddonWindowOrNull(JS::CurrentGlobalOrNull(aCx));}xpcReport->Init(aRep,nullptr,nsContentUtils::IsSystemCaller(aCx),win?win->AsInner()->WindowID():0);xpcReport->LogToConsole();}voidAutoJSAPI::ReportException(){if(!HasException()){return;}// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null// compartment when the destructor is called. However, the JS engine// requires us to be in a compartment when we fetch the pending exception.// In this case, we enter the privileged junk scope and don't dispatch any// error events.JS::Rooted<JSObject*>errorGlobal(cx(),JS::CurrentGlobalOrNull(cx()));if(!errorGlobal){if(mIsMainThread){errorGlobal=xpc::PrivilegedJunkScope();}else{errorGlobal=workers::GetCurrentThreadWorkerGlobal();}}JSAutoCompartmentac(cx(),errorGlobal);JS::Rooted<JS::Value>exn(cx());js::ErrorReportjsReport(cx());if(StealException(&exn)&&jsReport.init(cx(),exn,js::ErrorReport::WithSideEffects)){if(mIsMainThread){RefPtr<xpc::ErrorReport>xpcReport=newxpc::ErrorReport();RefPtr<nsGlobalWindow>win=xpc::WindowGlobalOrNull(errorGlobal);if(!win){// We run addons in a separate privileged compartment, but they still// expect to trigger the onerror handler of their associated DOM Window.win=xpc::AddonWindowOrNull(errorGlobal);}nsPIDOMWindowInner*inner=win?win->AsInner():nullptr;boolisChrome=nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(errorGlobal));xpcReport->Init(jsReport.report(),jsReport.toStringResult().c_str(),isChrome,inner?inner->WindowID():0);if(inner&&jsReport.report()->errorNumber!=JSMSG_OUT_OF_MEMORY){JS::RootingContext*rcx=JS::RootingContext::get(cx());DispatchScriptErrorEvent(inner,rcx,xpcReport,exn);}else{JS::Rooted<JSObject*>stack(cx(),xpc::FindExceptionStackForConsoleReport(inner,exn));xpcReport->LogToConsoleWithStack(stack);}}else{// On a worker, we just use the worker error reporting mechanism and don't// bother with xpc::ErrorReport. This will ensure that all the right// events (which are a lot more complicated than in the window case) get// fired.workers::WorkerPrivate*worker=workers::GetCurrentThreadWorkerPrivate();MOZ_ASSERT(worker);MOZ_ASSERT(worker->GetJSContext()==cx());// Before invoking ReportError, put the exception back on the context,// because it may want to put it in its error events and has no other way// to get hold of it. After we invoke ReportError, clear the exception on// cx(), just in case ReportError didn't.JS_SetPendingException(cx(),exn);worker->ReportError(cx(),jsReport.toStringResult(),jsReport.report());ClearException();}}else{NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");ClearException();}}boolAutoJSAPI::PeekException(JS::MutableHandle<JS::Value>aVal){MOZ_ASSERT_IF(mIsMainThread,IsStackTop());MOZ_ASSERT(HasException());MOZ_ASSERT(js::GetContextCompartment(cx()));if(!JS_GetPendingException(cx(),aVal)){returnfalse;}returntrue;}boolAutoJSAPI::StealException(JS::MutableHandle<JS::Value>aVal){if(!PeekException(aVal)){returnfalse;}JS_ClearPendingException(cx());returntrue;}#ifdef DEBUGboolAutoJSAPI::IsStackTop()const{returnScriptSettingsStack::TopNonIncumbentScript()==this;}#endif // DEBUGAutoEntryScript::AutoEntryScript(nsIGlobalObject*aGlobalObject,constchar*aReason,boolaIsMainThread):AutoJSAPI(aGlobalObject,aIsMainThread,eEntryScript),mWebIDLCallerPrincipal(nullptr)// This relies on us having a cx() because the AutoJSAPI constructor already// ran.,mCallerOverride(cx()){MOZ_ASSERT(aGlobalObject);if(aIsMainThread&&gRunToCompletionListeners>0){mDocShellEntryMonitor.emplace(cx(),aReason);}}AutoEntryScript::AutoEntryScript(JSObject*aObject,constchar*aReason,boolaIsMainThread):AutoEntryScript(xpc::NativeGlobal(aObject),aReason,aIsMainThread){}AutoEntryScript::~AutoEntryScript(){// GC when we pop a script entry point. This is a useful heuristic that helps// us out on certain (flawed) benchmarks like sunspider, because it lets us// avoid GCing during the timing loop.JS_MaybeGC(cx());}AutoEntryScript::DocshellEntryMonitor::DocshellEntryMonitor(JSContext*aCx,constchar*aReason):JS::dbg::AutoEntryMonitor(aCx),mReason(aReason){}voidAutoEntryScript::DocshellEntryMonitor::Entry(JSContext*aCx,JSFunction*aFunction,JSScript*aScript,JS::Handle<JS::Value>aAsyncStack,constchar*aAsyncCause){JS::Rooted<JSFunction*>rootedFunction(aCx);if(aFunction){rootedFunction=aFunction;}JS::Rooted<JSScript*>rootedScript(aCx);if(aScript){rootedScript=aScript;}nsCOMPtr<nsPIDOMWindowInner>window=do_QueryInterface(xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)));if(!window||!window->GetDocShell()||!window->GetDocShell()->GetRecordProfileTimelineMarkers()){return;}nsCOMPtr<nsIDocShell>docShellForJSRunToCompletion=window->GetDocShell();nsStringfilename;uint32_tlineNumber=0;js::AutoStableStringCharsfunctionName(aCx);if(rootedFunction){JS::Rooted<JSString*>displayId(aCx,JS_GetFunctionDisplayId(rootedFunction));if(displayId){if(!functionName.initTwoByte(aCx,displayId)){JS_ClearPendingException(aCx);return;}}}if(!rootedScript){rootedScript=JS_GetFunctionScript(aCx,rootedFunction);}if(rootedScript){filename=NS_ConvertUTF8toUTF16(JS_GetScriptFilename(rootedScript));lineNumber=JS_GetScriptBaseLineNumber(aCx,rootedScript);}if(!filename.IsEmpty()||functionName.isTwoByte()){constchar16_t*functionNameChars=functionName.isTwoByte()?functionName.twoByteChars():nullptr;docShellForJSRunToCompletion->NotifyJSRunToCompletionStart(mReason,functionNameChars,filename.BeginReading(),lineNumber,aAsyncStack,aAsyncCause);}}voidAutoEntryScript::DocshellEntryMonitor::Exit(JSContext*aCx){nsCOMPtr<nsPIDOMWindowInner>window=do_QueryInterface(xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)));// Not really worth checking GetRecordProfileTimelineMarkers here.if(window&&window->GetDocShell()){nsCOMPtr<nsIDocShell>docShellForJSRunToCompletion=window->GetDocShell();docShellForJSRunToCompletion->NotifyJSRunToCompletionStop();}}AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject*aGlobalObject):ScriptSettingsStackEntry(aGlobalObject,eIncumbentScript),mCallerOverride(nsContentUtils::GetCurrentJSContextForThread()){ScriptSettingsStack::Push(this);}AutoIncumbentScript::~AutoIncumbentScript(){ScriptSettingsStack::Pop(this);}AutoNoJSAPI::AutoNoJSAPI():ScriptSettingsStackEntry(nullptr,eNoJSAPI){ScriptSettingsStack::Push(this);}AutoNoJSAPI::~AutoNoJSAPI(){ScriptSettingsStack::Pop(this);}}// namespace domAutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL):mCx(nullptr){JS::AutoSuppressGCAnalysisnogc;MOZ_ASSERT(!mCx,"mCx should not be initialized!");MOZ_ASSERT(NS_IsMainThread());MOZ_GUARD_OBJECT_NOTIFIER_INIT;if(dom::IsJSAPIActive()){mCx=dom::danger::GetJSContext();}else{mJSAPI.Init();mCx=mJSAPI.cx();}}AutoJSContext::operatorJSContext*()const{returnmCx;}AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL):AutoJSAPI(){MOZ_ASSERT(NS_IsMainThread());MOZ_GUARD_OBJECT_NOTIFIER_INIT;DebugOnly<bool>ok=Init(xpc::UnprivilegedJunkScope());MOZ_ASSERT(ok,"This is quite odd. We should have crashed in the ""xpc::NativeGlobal() call if xpc::UnprivilegedJunkScope() ""returned null, and inited correctly otherwise!");}AutoSlowOperation::AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL):AutoJSAPI(){MOZ_ASSERT(NS_IsMainThread());MOZ_GUARD_OBJECT_NOTIFIER_INIT;Init();}voidAutoSlowOperation::CheckForInterrupt(){// JS_CheckForInterrupt expects us to be in a compartment.JSAutoCompartmentac(cx(),xpc::UnprivilegedJunkScope());JS_CheckForInterrupt(cx());}}// namespace mozilla